package cn.kdyzm.util.concurrent;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.function.Supplier;

/**
 * @author kdyzm
 * @date 2022/11/3
 */
@Slf4j
public class ConcurrentWorker {

    private List<Task> workers = new ArrayList<>();

    public static ConcurrentWorker runner() {
        return new ConcurrentWorker();
    }

    public <R> ConcurrentWorker addTask(Consumer<? super R> action, Supplier<R> value) {
        Task<R> worker = new Task<>(action, value);
        this.workers.add(worker);
        return this;
    }

    public <R> ConcurrentWorker addTask(Runnable runnable) {
        Task<R> worker = new Task<>(runnable);
        this.workers.add(worker);
        return this;
    }

    public void run() {
        workers.forEach(item -> {
            int taskType = item.getTaskType();
            CompletableFuture completableFuture = null;
            switch (taskType) {
                case TaskType.RETURN_VALUE:
                    completableFuture = CompletableFuture.supplyAsync(item.getValue());
                    break;
                case TaskType.VOID_RETURN:
                    completableFuture = CompletableFuture.runAsync(item.getRunnable());
                    break;
                default:
                    break;
            }
            item.setCompletableFuture(completableFuture);
        });
        workers
                .stream()
                .map(
                        item -> {
                            int taskType = item.getTaskType();
                            switch (taskType) {
                                case TaskType.RETURN_VALUE:
                                    return item.completableFuture.thenAccept(item.getAction());
                                default:
                                    return item.completableFuture.thenAccept(temp->{
                                        //空
                                    });
                            }
                        }
                )
                .forEach(CompletableFuture::join);
    }

    @Data
    public static class Task<R> {
        private Consumer<? super R> action;
        private Supplier<R> value;
        private CompletableFuture<R> completableFuture;
        private Runnable runnable;
        private int taskType;

        public Task(Consumer<? super R> action, Supplier<R> value) {
            this.action = action;
            this.value = value;
            this.taskType = TaskType.RETURN_VALUE;
        }


        public Task(Runnable runnable) {
            this.runnable = runnable;
            this.taskType = TaskType.VOID_RETURN;
        }
    }


    public static class TaskType {

        /**
         * 有返回值的
         */
        public static final int RETURN_VALUE = 1;

        /**
         * 没有返回值的
         */
        public static final int VOID_RETURN = 2;
    }
}
